package labox.innovation.gameserver.model;

import java.util.List;

import javolution.util.FastList;
import labox.innovation.config.Config;
import labox.innovation.gameserver.model.actor.L2Attackable;
import labox.innovation.gameserver.model.actor.L2Character;
import labox.innovation.gameserver.model.actor.L2Playable;
import labox.innovation.gameserver.model.actor.instance.FuzePcInstance;
import labox.innovation.gameserver.model.base.Sex;
import labox.innovation.gameserver.model.itemcontainer.PcInventory;
import labox.innovation.gameserver.network.SystemMessageId;
import labox.innovation.gameserver.network.clientpackets.Say2;
import labox.innovation.gameserver.network.serverpackets.CreatureSay;
import labox.innovation.gameserver.network.serverpackets.L2GameServerPacket;
import labox.innovation.gameserver.network.serverpackets.PartyChangeDistribution;
import labox.innovation.gameserver.network.serverpackets.PartyLeaderPacket;
import labox.innovation.gameserver.network.serverpackets.PartySmallWindowAdd;
import labox.innovation.gameserver.network.serverpackets.PartySmallWindowAll;
import labox.innovation.gameserver.network.serverpackets.PartySmallWindowDelete;
import labox.innovation.gameserver.network.serverpackets.PartySmallWindowDeleteAll;
import labox.innovation.gameserver.network.serverpackets.SystemMessage;
import labox.innovation.gameserver.util.Util;
import labox.innovation.util.Rnd;

/**
 * @author ljsh
 * @date 2010-4-12
 * @version 1.0
 * @description 关于队伍的一些操作
 */
/**
 * @author Lian
 *
 */
public class L2Party {

	private static final float _gmcoefficient = 0.05f; // 男女搭配系数

	private FastList<FuzePcInstance> _members;

	private boolean _pendingInvitation;

	private int _partyLvl;

	private int _itemDistribution;// 队伍物品分配方式

	private L2CommandChannel _commandChannel;

	public static final int ITEM_LOOTER = 0;// 自由分配

	public static final int ITEM_RANDOM = 1;// 随机分配
	public static final int PARTY_MEMBER_LIMIT = 5;// 队伍人数上限

	/**
	 * constructor ensures party has always one member - leader
	 * 
	 * @param leader
	 * @param itemDistributionMode
	 */
	public L2Party(FuzePcInstance leader) {
		_itemDistribution = ITEM_LOOTER;
		getPartyMembers().add(leader);
		_partyLvl = leader.getLevel();
	}

	/**
	 * 判断subMembers中是否有异性
	 * 
	 * @param player
	 * @return
	 */
	private boolean isHeterosexual(List<L2Playable> rewardedMembers) {
		Sex sex = null;
		FuzePcInstance pc = null;
		for (L2Playable member : rewardedMembers) {
			pc = (FuzePcInstance) member;
			if (sex == null) {
				sex = pc.getAppearance().getSex();
			} else if (sex != pc.getAppearance().getSex()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * returns number of party members
	 * 
	 * @return
	 */
	public int getMemberCount() {
		return getPartyMembers().size();
	}

	/**
	 * returns number of players that already been invited, but not replied yet
	 * 
	 * @return
	 */
	public boolean getPendingInvitation() {
		return _pendingInvitation;
	}

	/**
	 * decrease number of players that already been invited but not replied yet
	 * happens when: player join party or player decline to join
	 */
	public void setPendingInvitation(boolean val) {
		_pendingInvitation = val;
	}

	/**
	 * returns all party members
	 * 
	 * @return
	 */
	public FastList<FuzePcInstance> getPartyMembers() {
		if (_members == null)
			_members = new FastList<FuzePcInstance>();

		return _members;
	}

	/**
	 * get random member from party 从队伍中随机 获得一个成员，该成员可以获取掉落物品
	 * 
	 * @return
	 */
	private FuzePcInstance getCheckedRandomMember(int ItemId, int count, L2Character target, boolean check) {
		List<FuzePcInstance> availableMembers = new FastList<FuzePcInstance>();
		for (FuzePcInstance member : getPartyMembers()) {
			// 检测队伍成员背包是否可以放下物品，是否在可分配区域内
			if (check) {
				if (member.getInventory().validateCapacityByItemId(ItemId, count) && Util.checkIfInRange(Config.ALT_PARTY_RANGE2, target, member))
					availableMembers.add(member);
			} else {
				if (Util.checkIfInRange(Config.ALT_PARTY_RANGE2, target, member)) {
					availableMembers.add(member);
				}
			}
		}
		if (!availableMembers.isEmpty())
			return availableMembers.get(Rnd.get(availableMembers.size()));// 返回随机的一个角色获取该物品
		else
			return null;
	}


	/**
	 * @param player
	 * @param ItemId 模板Id
	 * @param count 数量
	 * @param spoil
	 * @param target
	 * @param check 是否需要检测背包空间
	 * @return
	 */
	private FuzePcInstance getActualLooter(FuzePcInstance player, int ItemId, int count, boolean spoil, L2Character target, boolean check) {
		FuzePcInstance looter = player;
		switch (_itemDistribution) {
		case ITEM_LOOTER:
			looter = player;// 自由分配，谁杀的怪物谁所有
			break;
		case ITEM_RANDOM:
			if (!spoil)
				looter = getCheckedRandomMember(ItemId, count, target, check);
			break;
		}
		if (looter == null)
			looter = player;
		return looter;
	}

	/**
	 * true if player is party leader
	 * 
	 * @param player
	 * @return
	 */
	public boolean isLeader(FuzePcInstance player) {
		return (getLeader().equals(player));
	}

	/**
	 * Returns the Object ID for the party leader to be used as a unique
	 * identifier of this party
	 * 
	 * @return int
	 */
	public long getPartyLeaderOID() {
		return getLeader().getObjectId();
	}

	public FuzePcInstance getPlayerById(long id) {
		for (FuzePcInstance member : getPartyMembers()) {
			if (member.getObjectId() == id)
				return member;
		}
		return null;
	}

	/**
	 * Broadcasts packet to every party member
	 * 
	 * @param msg
	 *            向队每个伍成员发送服务器消息的接口
	 */
	public void broadcastToPartyMembers(L2GameServerPacket msg) {
		for (FuzePcInstance member : getPartyMembers()) {
			if (member != null && member.isOnline() == 1 ? true : false)
				member.sendPacket(msg);
		}
	}

	/**
	 * 向队伍成员广播谁是队长
	 */
	public void broadcastToPartyMembersNewLeader() {
		for (FuzePcInstance member : getPartyMembers()) {
			if ((member != null) && (member != getLeader() && member.isOnline() == 1 ? true : false)) {
				member.sendPacket(new PartyLeaderPacket(getLeader()));
			}
		}
	}

	public void broadcastCSToPartyMembers(CreatureSay msg, FuzePcInstance broadcaster) {
		for (FuzePcInstance member : getPartyMembers()) {
			if (member != null && !BlockList.isBlocked(member, broadcaster)) {
				if (member.getSwitchByChatCode(Say2.PART_CHANNAL))
					member.sendPacket(msg);
			}

		}
	}

	/**
	 * Send a Server->Client packet to all other L2PcInstance of the Party.<BR>
	 * <BR>
	 */
	public void broadcastToPartyMembers(FuzePcInstance player, L2GameServerPacket msg) {
		for (FuzePcInstance member : getPartyMembers()) {
			if (member != null && member != player)
				member.sendPacket(msg);
		}
	}

	/**
	 * adds new member to party
	 * 
	 * @param player
	 */
	public void addPartyMember(FuzePcInstance player) {

		SystemMessage msg = new SystemMessage(SystemMessageId.YOU_JOINED_S1_PARTY);
		msg.addString(getLeader().getName());
		player.sendPacket(msg);

		msg = new SystemMessage(SystemMessageId.C1_JOINED_PARTY);
		msg.addString(player.getName());
		broadcastToPartyMembers(msg);

		// add player to party, adjust party level
		getPartyMembers().add(player);
		if (player.getLevel() > _partyLvl) {
			_partyLvl = player.getLevel();
		}

		// update partySpelled
		for (FuzePcInstance member : getPartyMembers()) {
			if (member != null && member != player) {
				member.sendPacket(new PartySmallWindowAdd(player));
				member.getRadar().addMarker(player);
			} else
				member.sendPacket(new PartySmallWindowAll(member, this));
		}
		getLeader().sendPacket(new PartyLeaderPacket(getLeader()));
	}

	/**
	 * @param party
	 *            判断队伍人数是否少于2人，如果是则解散队伍
	 */
	public void autobreakParty(L2Party party) {
		if (party.getMemberCount() < 2) {
			for (FuzePcInstance temp : party.getPartyMembers()) {
				party.removePartyMember(temp);
			}
		}
	}

	/**
	 * Remove player from party
	 * 
	 * @param player
	 */
	public void removePartyMember(FuzePcInstance player) {
		if (player == null) {
			getPartyMembers().remove(player);
			return;
		}
		if (getPartyMembers().contains(player)) {
			boolean isLeader = isLeader(player);
			getPartyMembers().remove(player);
			SystemMessage msg = new SystemMessage(SystemMessageId.YOU_LEFT_PARTY);
			player.sendPacket(msg);
			player.setParty(null);
			for (FuzePcInstance member : getPartyMembers()) {
				if (member != null) {
					member.sendPacket(new PartySmallWindowDelete(player));
					member.getRadar().removeMarker(player);
					player.getRadar().removeMarker(member);
				}
			}
			if (player.isOnline() == 1 ? true : false) {
				player.sendPacket(new PartySmallWindowDeleteAll());
			}

			msg = new SystemMessage(SystemMessageId.C1_LEFT_PARTY);
			msg.addString(player.getName());
			broadcastToPartyMembers(msg);
			if (isLeader && getPartyMembers().size() > 1) {
				changePartyLeader();// 随机指定一名队长
				return;
			}
			if (getMemberCount() == 1) {
				FuzePcInstance leader = getLeader();
				if (leader != null) {
					leader.sendPacket(new PartySmallWindowDeleteAll());
					leader.setParty(null);
				}
			}
		}
	}

	/**
	 * Change party leader (used for string arguments)
	 * 
	 * @param name
	 *            随机抽取一个人成为队长
	 */
	public void changePartyLeader() {
		int index = Rnd.get(getMemberCount());
		FuzePcInstance player = getPlayerById(index);
		if (player != null) {
			if (getPartyMembers().contains(player)) {
				if (!isLeader(player)) {
					// Swap party members
					FuzePcInstance temp;
					int p1 = getPartyMembers().indexOf(player);
					temp = getLeader();
					getPartyMembers().set(0, getPartyMembers().get(p1));
					getPartyMembers().set(p1, temp);

				}
				SystemMessage msg = new SystemMessage(SystemMessageId.C1_HAS_BECOME_A_PARTY_LEADER);
				msg.addString(getLeader().getName());
				broadcastToPartyMembers(msg);// 向队伍成员发送消息xxx成为队长
				broadcastToPartyMembersNewLeader();
			} else {
				player.sendPacket(new SystemMessage(SystemMessageId.YOU_CAN_TRANSFER_RIGHTS_ONLY_TO_ANOTHER_PARTY_MEMBER));
			}
		}

	}

	/**
	 * @param charid
	 *            指定一个队长
	 */
	public void setLeader(long charid) {
		FuzePcInstance player = getPlayerById(charid);
		if (player != null) {
			if (getPartyMembers().contains(player)) {
				if (isLeader(player)) {
					player.sendPacket(new SystemMessage(SystemMessageId.YOU_CANNOT_TRANSFER_RIGHTS_TO_YOURSELF));
				} else {
					// Swap party members
					FuzePcInstance temp;
					int p1 = getPartyMembers().indexOf(player);
					temp = getLeader();
					getPartyMembers().set(0, getPartyMembers().get(p1));
					getPartyMembers().set(p1, temp);
					SystemMessage msg = new SystemMessage(SystemMessageId.C1_HAS_BECOME_A_PARTY_LEADER);
					msg.addString(getLeader().getName());
					broadcastToPartyMembers(msg);// 向队伍成员发送消息xxx成为队长
					broadcastToPartyMembersNewLeader();
				}
			} else {
				player.sendPacket(new SystemMessage(SystemMessageId.YOU_CAN_TRANSFER_RIGHTS_ONLY_TO_ANOTHER_PARTY_MEMBER));
			}
		}
	}

	/**
	 * distribute item(s) to party members
	 * 
	 * @param player
	 * @param item
	 *            分配物品给队伍成员
	 */
	public void distributeItem(FuzePcInstance player, ItemDropManage.RewardItem item, boolean spoil, L2Attackable target) {
		if (item == null)
			return;
		if (item.getItemId() == PcInventory.MONEY_SLIVER_ID) // 银子
		{
			distributeAdena(player, item, target);
			return;
		}
		FuzePcInstance looter = getActualLooter(player, item.getItemId(), item.getCount(), spoil, target, true);// 获取物品的所有者
		looter.addItem(spoil ? ItemDropManage.DROP_STR : ItemDropManage.DROP_STR_RAID, item.getItemId(), item.getCount(), player, true);
	}

	/**
	 * distribute adena to party members
	 * 
	 * @param adena
	 *            钱币的分配
	 */
	public void distributeAdena(FuzePcInstance player, ItemDropManage.RewardItem item, L2Character target) {
		FuzePcInstance looter = getActualLooter(player, item.getItemId(), item.getCount(), false, target, false);
		looter.addMoneySilver("party", item.getCount(), null, false);

	}

	/**
	 * @param xpReward
	 * @param rewardedMembers
	 * @param target
	 * @param killer
	 *            分配组队经验
	 */
	public void distributeXpAndSp(int xpReward, List<L2Playable> rewardedMembers, L2Attackable target, L2Character killer) {
		boolean isheter = isHeterosexual(rewardedMembers);
		int totalLevel = getCurrentSceneTotalLevel(rewardedMembers);
		for (L2Character member : rewardedMembers) {
			if (member.isDead())
				continue;
			int addexp = 0;
			if (member instanceof FuzePcInstance) {
				FuzePcInstance temp = (FuzePcInstance) member;
				int evelDiff = temp.getLevel() - target.getLevel();
				int exp = xpReward - xpReward * Math.min(5, Math.max(3, evelDiff) - 3) / 5;
				if (isheter)// 判断队伍是否有异性
				{
					double temexp = (exp * (1 + rewardedMembers.size() * 0.2 + _gmcoefficient) * temp.getLevel() / totalLevel) * (temp.getStat().getKillMobExpRate() + Config.ALT_GAME_EXPONENT_XP + target.getScene().getExpRate()) + temp.getStat().getKillMobExp();
					addexp = (int) temexp;
				} else {
					double temexp = (exp * (1 + rewardedMembers.size() * 0.2) * temp.getLevel() / totalLevel) * (temp.getStat().getKillMobExpRate() + Config.ALT_GAME_EXPONENT_XP + target.getScene().getExpRate()) + temp.getStat().getKillMobExp();
					addexp = (int) temexp;
				}
				temp.addExp((int) addexp);
				SystemMessage msg = new SystemMessage(SystemMessageId.GET_EXP_COUNT);
				msg.addNumber(addexp);
				temp.sendPacket(msg);
			}
		}

	}

	/**
	 * refresh party level 重新计算队伍等级，为队伍中最高等级。
	 */
	public void recalculatePartyLevel() {
		int newLevel = 0;
		for (FuzePcInstance member : getPartyMembers()) {
			if (member == null) {
				getPartyMembers().remove(member);
				continue;
			}

			if (member.getLevel() > newLevel)
				newLevel = member.getLevel();
		}
		_partyLvl = newLevel;
	}

	public int getLevel() {
		return _partyLvl;
	}

	public int getLootDistribution() {
		return _itemDistribution;
	}

	/**
	 * @param itemDistribution
	 * @return 设置队伍分配方式
	 */
	public void setLootDistribution(int itemDistribution) {
		_itemDistribution = itemDistribution;
		broadcastToPartyMembers(new PartyChangeDistribution(this));
	}

	/**
	 * 处理在组队状态下离线
	 */
	public void processLogout(FuzePcInstance player) {
		if (getMemberCount() >= 3) {
			L2PartyManager.addPartyMemberExDropped(player);// 进行登出处理
		} else if (getMemberCount() < 3) {
			broadcastToPartyMembers(new PartySmallWindowDeleteAll());
			removePartyMember(player);
		}
	}

	public boolean isInCommandChannel() {
		return _commandChannel != null;
	}

	public L2CommandChannel getCommandChannel() {
		return _commandChannel;
	}

	public void setCommandChannel(L2CommandChannel channel) {
		_commandChannel = channel;
	}

	public FuzePcInstance getLeader() {
		if (_members != null && !_members.isEmpty())
			return _members.getFirst();
		return null;
	}

	/**
	 * 获取与指定玩家同场景的所有队伍成员等级总和
	 * 
	 * @param player
	 * @return
	 */
	public int getCurrentSceneTotalLevel(List<L2Playable> rewardedMembers) {
		int totalLevel = 0;
		for (L2Playable playable : rewardedMembers) {
			totalLevel += playable.getLevel();
		}
		return totalLevel;
	}
}
